<script setup lang="ts">
  import { PropType, onMounted, ref, watch } from 'vue'
  import useAddressOptions from './services/useAddressOptions'
  import { CascaderProps, ElCascader } from 'element-plus'

  const props = defineProps({
    checkStrictly: {
      type: Boolean,
      default: () => false,
    },
    address: {
      type: Object as PropType<{ province: string; city: string; area: string; town: string }>,
      default: () => {
        return {
          province: '',
          city: '',
          area: '',
          town: '',
        }
      },
    },
    clear: {
      type: Boolean,
      default: () => false,
    },
    disabled: {
      type: Boolean,
      default: () => false,
    },
  })

  const emits = defineEmits<{
    (e: 'change', value: { province: string; city: string; area: string; town: string }): void
  }>()

  const cascaderRef = ref<InstanceType<typeof ElCascader> | null>(null)
  const { addressOptions, getAddressOptionsLoading, getAddressOptions } = useAddressOptions()
  const addressCodes = ref<Array<string>>([])
  const addressNames = ref({
    province: '',
    city: '',
    area: '',
    town: '',
  })
  const cascaderProps: CascaderProps = {
    checkStrictly: props.checkStrictly,
    value: 'code',
    label: 'name',
  }

  const onAddressChange = () => {
    if (cascaderRef.value && cascaderRef.value.getCheckedNodes(false).length > 0) {
      addressNames.value = {
        province: cascaderRef.value.getCheckedNodes(false)[0].pathLabels[0],
        city: cascaderRef.value.getCheckedNodes(false)[0].pathLabels[1],
        area: cascaderRef.value.getCheckedNodes(false)[0].pathLabels[2],
        town: cascaderRef.value.getCheckedNodes(false)[0].pathLabels[3] || '',
      }
    }
    if (!addressCodes.value) {
      clearAddress()
    }
    emits('change', addressNames.value)
  }

  const clearAddress = () => {
    addressCodes.value = []
    Object.assign(addressNames.value, {
      province: '',
      city: '',
      area: '',
      town: '',
    })
  }

  const addressEchoLoading = ref(false)
  const addressEcho = () => {
    addressCodes.value.length = 0
    addressEchoLoading.value = true
    addressOptions.value.forEach((province) => {
      if (province.name === props.address.province) {
        addressCodes.value.push(province.code)

        province.children.forEach((city) => {
          if (city.name === props.address.city) {
            addressCodes.value.push(city.code)

            city.children.forEach((area) => {
              if (area.name === props.address.area) {
                addressCodes.value.push(area.code)

                area.children.forEach((town) => {
                  if (town.name === props.address.town) {
                    addressCodes.value.push(town.code)
                  }
                })
              }
            })
          }
        })
      }
    })
    addressEchoLoading.value = false
  }

  watch(
    () => props.address,
    (value) => {
      if (value.province && value.area && value.city) {
        addressEcho()
      }
    },
    { immediate: true },
  )

  onMounted(() => {
    getAddressOptions().then(() => {
      if (props.address.province && props.address.city && props.address.area) {
        addressEcho()
      }
    })
  })

  defineExpose({
    clearAddress,
  })
</script>

<template>
  <el-cascader
    ref="cascaderRef"
    v-model="addressCodes"
    :disabled="addressEchoLoading || getAddressOptionsLoading || props.disabled"
    placeholder="请选择地址"
    :props="cascaderProps"
    :options="addressOptions"
    :clearable="props.clear"
    @change="onAddressChange"
  />
</template>
